package sync_go_pool

import (
	"fmt"
	"sync"
	"time"
)

type Task func()

type ThreadPool struct {
	workerCount int
	taskQueue   chan Task
	wg          sync.WaitGroup
}

func NewThreadPool(workerCount, maxTaskNum int) *ThreadPool {
	pool := &ThreadPool{
		workerCount: workerCount,
		taskQueue:   make(chan Task, maxTaskNum),
	}

	for i := 0; i < workerCount; i++ {
		go pool.worker()
	}

	return pool
}

func (p *ThreadPool) worker() {
	for task := range p.taskQueue {
		task()      // execute task
		p.wg.Done() // Task complete, reduce waiting group count
	}
}

func (p *ThreadPool) AddTask(task Task) {
	p.wg.Add(1)
	p.taskQueue <- task // add a task to queue.
}

func (p *ThreadPool) Wait() {
	p.wg.Wait() //wait for all tasks to complete .
}

//usage
func main() {
	workerCount := 3
	maxTaskNum := 20
	pool := NewThreadPool(workerCount, maxTaskNum)

	for i := 0; i < 50; i++ {
		taskNum := i + 1000
		pool.AddTask(func() {
			fmt.Printf("Task %d is running\n", taskNum)
			time.Sleep(1 * time.Second)
			fmt.Printf("Task %d is done\n", taskNum)
		})
	}

	pool.Wait() // wait for all tasks to complete.
}
